#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include "chr.h"

//设备名称
#define MYCDEV_NAME "mycdev_simple"
//设备类名称
#define MYCDEV_CLASS "mycdev_class"
//设备数量
#define CDEV_NUM 1

// // #define CMD_IOC_MAGIC	'k'
// #define UNREVERSE _IO('k', 0)
// #define REVERSE _IO('k', 1)

//设备类
static struct class *mycdev_class;
//所有设备的数组
static struct cdev cdevs[CDEV_NUM];
static struct device devices[CDEV_NUM];
 
//设备号
static dev_t dev_num;
static  char mybuf[100]="123";
static  char buf_message[1024];
static int mode = 1;
 
static int strLength(const char *s);
static void reverse(char* arr);
static int mycdev_open(struct inode *inode, struct file *file);
static ssize_t mycdev_read(struct file *file, char __user *buff, size_t len , loff_t *pos);
static ssize_t mycdev_write(struct file *, const char __user *buff, size_t len, loff_t *pos);
static int mycdev_release(struct inode *inode, struct file *file);
static ssize_t mydevice_show(struct device *dev, struct device_attribute *attr,char *buf);
static ssize_t mydevice_store(struct device *dev, struct device_attribute *attr,const char *buf, size_t count);
static DEVICE_ATTR(mydevice, 0644, mydevice_show, mydevice_store);
static long mycdev_ioctl(struct file *fp, unsigned int cmd, unsigned long arg);

static struct file_operations op_f={
	.read=mycdev_read,
	.write=mycdev_write,
	.open=mycdev_open,
	.release=mycdev_release,
    .unlocked_ioctl = mycdev_ioctl,
};




//模块初始化函数
static int __init simple_chardev_init(void)
{
	int i,retVal,ret;
    /*设备号*/
    dev_t curr_devnum; 
 
    /*请求内核分配设备号*/
    retVal=alloc_chrdev_region(&dev_num,0,CDEV_NUM,MYCDEV_CLASS);
    if(retVal!=0)
    {
    	printk("alloc_chrdev_region error %d\n",retVal);
    	return retVal;
    }
 
    //为字符设备创建设备类,在/sys/class中可见
    mycdev_class=class_create(THIS_MODULE,MYCDEV_CLASS);
 
    /*创建字符设备结构并注册到内核*/
    for(i=0;i<CDEV_NUM;i++)
    {
    	/*初始化字符设备*/
    	cdev_init(&cdevs[i],&op_f);
    	cdevs[i].owner=THIS_MODULE;
 
    	/*设置设备号*/
    	curr_devnum=MKDEV(MAJOR(dev_num),MINOR(dev_num)+i);
    	/*添加设备到内核*/
    	retVal=cdev_add(&cdevs[i],curr_devnum,1);
        printk("cdev_add retVal %d\n",retVal);
 
    	/*创建设备节点*/
    	devices[i]=*(device_create(mycdev_class,NULL,curr_devnum,NULL,MYCDEV_NAME "%d",i));
        printk("device_create %p\n",&devices[i]);

        ret = device_create_file(&devices[i], &dev_attr_mydevice);
    }
	return retVal;
}
 
static void __exit simple_chardev_exit(void)
{
    dev_t _devnum;
    int i;
 
    for(i=0;i<CDEV_NUM;i++)
    {
        _devnum=MKDEV(MAJOR(dev_num),MINOR(dev_num)+i);
        device_destroy(mycdev_class, _devnum);
        cdev_del(&(cdevs[i]));
    }
    class_destroy(mycdev_class);
 
    unregister_chrdev_region(dev_num,CDEV_NUM);
    printk("simple_chardev_exit\n");
    return;
}
 
 
/*打开设备*/
static int mycdev_open(struct inode *inode, struct file *file)
{
	/*打印一条消息到内核日志*/
	printk("call mycdev_open\n");
	return 0;
}
 
/*读操作*/
static ssize_t mycdev_read(struct file *file, char __user *buff, size_t len , loff_t *pos)
{
    if(mode==1)
    {
	    printk("unreverse read\n");        
        reverse(buf_message);        
    }

    int count,retVal;
    // const char *s1="from mycdev_simple!";
	printk("call mycdev_read\n");
	count=strLength(buf_message);
	retVal=copy_to_user(buff,buf_message,count+1);
    if(retVal==-EFAULT)
    {
        printk("mycdev_read error\n");
        return -EFAULT;
    }
	return count+1;

}
 
/*写操作*/
static ssize_t mycdev_write(struct file *file, const char __user *buff, size_t len, loff_t *pos)
{
	// char *buffer;
    int retVal;
	// buffer=NULL;
    
 
    printk("call mycdev_write\n");
    // buffer = (char*)kmalloc(len, GFP_KERNEL);
    // if(buffer==NULL)
    // {
    // 	printk("kmalloc error\n");
    // 	return -EFAULT;
    // }
    memset(buf_message,0,1024); 
    retVal=copy_from_user(buf_message, buff, len);

    if(retVal==-EFAULT)
    {
        printk("mycdev_write error\n");
        return -EFAULT;
    }
    // printk("recv %s\n",buffer);
    return len;
}

static ssize_t mydevice_show(struct device *dev, struct device_attribute *attr,char *buf)
{
    if(mode ==0)
    {
        printk("show reverse");
        reverse(mybuf); 
    }
    printk("show");
    return sprintf(buf, "%s\n", mybuf);
}
static ssize_t mydevice_store(struct device *dev, struct device_attribute *attr,const char *buf, size_t count)
{
    memset(mybuf,0,100);
    sprintf(mybuf, "%s", buf);

    return count;
}
 
/*关闭文件*/
static int mycdev_release(struct inode *inode, struct file *file)
{
	printk("call mycdev_release\n");
	return 0;
}

//控制模式
static long mycdev_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
{
	// int rc = 0;
	// int arg_w;
	// const int arg_r = 566;
	// if (_IOC_TYPE(cmd) != CMD_IOC_MAGIC) {
	// 	pr_err("%s: command type [%c] error.\n", __func__, _IOC_TYPE(cmd));
	// 	return -ENOTTY;
	// }
    printk("ioctl"); 
	switch(cmd) {
		case UNREVERSE:
            printk("UNREVERSE");        
			mode = 0;
			break;
		case REVERSE:
            printk("REVERSE");
			mode = 1;
			break;
		default:
			return -ENOTTY;
	}
	return 0;
}
 
/*计算字符串长度*/
static int strLength(const char *s)
{
	int len=0;
	// while((*s)!=0)
	// {
	// 	s++;
	// 	len++;
	// }
    for(int i=0;s[i]!='\0',i++)
    {
        len++;
    }
	return len;
}

static void reverse(char* arr)
{
	char *left = arr;
	char *right = arr+strlen(arr)-1;
 
 
	while(left<right)
	{
		char tmp = *left;
		*left = *right;
		*right = tmp;
 
 
		left++;
		right--;
	}
}






 
module_init(simple_chardev_init);
module_exit(simple_chardev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("xxxxxx");
MODULE_DESCRIPTION("内核描述");